#pragma once

#include "Comm.hpp"
#include "Acceptor.hpp"
#include "Connection.hpp"
#include "LoopThreadPool.hpp"


class TcpServer
{
private:
    using task_t = std::function<void()>;
    using ConnectedCallback = std::function<void(const PtrConnection&)>;
    using MessageCallback = std::function<void(const PtrConnection&, Buffer*)>;
    using ClosedCallback = std::function<void(const PtrConnection&)>;
    using AnyEventCallback = std::function<void(const PtrConnection&)>;

    void NewConnection(int fd)
    {
        PtrConnection conn = std::make_shared<Connection>(_next_id, _pool.NextLoop(), fd);

        conn->SetMessageCallback(_message_callback);
        conn->SetClosedCallback(_closed_callback);
        conn->SetConnectedCallback(_connected_callback);
        conn->SetAnyEventCallback(_any_event_callback);
        conn->SetSrvClosedCallback(std::bind(&TcpServer::RemoveConnection, this, std::placeholders::_1));

        if (_enable_inactive_release) conn->EnableInactiveRelease(_timeout);
        conn->Established();

        _conns.insert({ _next_id, conn });

        _next_id++;
    }

    void RemoveConnectionInLoop(const PtrConnection &conn)
    {
        int id = conn->GetID();
        auto it = _conns.find(id);
        if (it != _conns.end())
            _conns.erase(it);
    }

    void RemoveConnection(const PtrConnection &conn)
    {
        LOG(DEBUG, "TcpServer::RemoveConnection\n");
        _base_loop.RunInLoop(std::bind(&TcpServer::RemoveConnectionInLoop, this, conn));
    }

    void RunAfterInLoop(const task_t& task, int delay) { _base_loop.TimerAdd(++_next_id, delay, task); }

public:
    TcpServer(in_port_t port)
        : _port(port), 
          _next_id(0), 
          _base_loop(), 
          _acceptor(&_base_loop, _port), 
          _pool(&_base_loop), 
          _enable_inactive_release(false)
    {
        _acceptor.SetAcceptCallback(std::bind(&TcpServer::NewConnection, this, std::placeholders::_1));
        _acceptor.Listen();
    }

    void SetThreadCount(int count) {  return _pool.SetThreadCount(count); }

    void SetConnectedCallback(const ConnectedCallback& cb) { _connected_callback = cb; }

    void SetMessageCallback(const MessageCallback& cb) { _message_callback = cb; }

    void SetClosedCallback(const ClosedCallback& cb) { _closed_callback = cb; }

    void SetAnyEventCallback(const AnyEventCallback& cb) { _any_event_callback = cb; }

    void EnableInactiveRelease(int timeout)
    {
        _timeout = timeout;
        _enable_inactive_release = true;
    }

    void RunAfter(const task_t& task, int delay)
    {
        LOG(DEBUG, "TcpServer::RunAfterInLoop\n");
        _base_loop.RunInLoop(std::bind(&TcpServer::RunAfterInLoop, this, task, delay));
    }

    void Start()
    {
        LOG(INFO, "TcpServer Start!\n");
        _pool.Create();
        _base_loop.Start();
    }

    ~TcpServer()
    {}

private:
    in_port_t _port;
    uint64_t _next_id;                                   // 自动增长的连接 ID 
    
    EventLoop _base_loop;                                // 主线程的负责对监听事件的处理 
    Acceptor _acceptor;                                  // 监听套接字的管理对象 
    LoopThreadPool _pool;                                // 从属 EventLoop 线程池 
    
    int _timeout;                                        // 非活跃连接的超时时间 
    bool _enable_inactive_release;                       // 是否启动了非活跃连接释放的判断标志 
    
    std::unordered_map<uint64_t, PtrConnection> _conns;  // 保存对所有连接对应的 share_ptr 对象 

    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    AnyEventCallback _any_event_callback;
};

